using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using OpenComposite.Repository.Properties;
using System.Web.Services.Discovery;
using System.Net;
using System.Collections;
using System.Web.Services.Description;
using System.Xml;
using System.IO;
using System.Xml.Schema;
using System.ServiceModel.Description;
using System.ServiceModel.Channels;
using System.Runtime.Serialization;
using System.CodeDom;
using System.ServiceModel;
using System.Web.Services.Protocols;
using System.Configuration;

namespace OpenComposite.EII.RepositoryUIs
{
	public partial class FormCreateNewWebService : Forms.FormCreateNewBase
	{
		#region Initialization
		public FormCreateNewWebService(Repository.WebService webService, int idRepository, bool bAllowContinue)
			: base(webService, webService, bAllowContinue)
		{
			InitializeComponent();

			_idRepository = idRepository;

			init();
		}
		private void init()
		{
			_webmethods = new List<OpenComposite.EII.Repository.WebMethod>();

			dgvWebMethods.AutoGenerateColumns = false;
			dgvWebMethods.DataSource = new BindingList<Repository.WebMethod>(_webmethods);

			this.DialogResult = DialogResult.Cancel;
		}
		#endregion

		#region Variables
		private int _i = 0;
		private int _idRepository = -1;

		private List<Repository.WebMethod> _webmethods;

		private System.Web.Services.Description.ServiceDescription _wsdl = null;
		#endregion

		#region Methods

		protected override void OnSaveClose(CancelEventArgs e)
		{
			if ( save() ) {
				base.OnSaveClose(e);
			} else {
				e.Cancel = true;
			}
		}
		protected override void OnSaveContinue(CancelEventArgs e)
		{
			if ( save() ) {
				base.OnSaveContinue(e);
			} else {
				e.Cancel = true;
			}
		}
		protected override void OnCancel()
		{
			foreach ( Repository.WebMethod meth in _webmethods ) {
				meth.Destroy(false);
			}
			base.OnCancel();
		}
		private bool save()
		{
			bool ok = false;

			ok = saveWebService();
			if ( ok )
				ok = saveWebMethods();

			return ok;
		}
		private bool saveWebService()
		{
			Repository.WebService ws = this.RepositoryItem as Repository.WebService;
			if ( ws == null )
				return false;
			else {
				ws.DomainId = this.DomainID;
				return ws.Save();
			}
		}
		private bool saveWebMethods()
		{
			Repository.WebService ws = this.RepositoryItem as Repository.WebService;
			if ( ws == null )
				return false;

			bool ok = false;
			foreach ( Repository.WebMethod meth in _webmethods ) {
				meth.DomainId = this.DomainID;
				ok = meth.Save();
				if ( ok )
					Global.Data.AddRepositoryHierarchy(ws, meth, _idRepository);
				else
					continue;
			}
			return ok;
		}

		private void discoverWS()
		{
			Repository.WebService ws = this.RepositoryItem as Repository.WebService;
			RepositoryService repSvc = this.RepositoryService;
			if ( ws == null )
				throw new Exception("Repository Item is not a web service.");
			if ( repSvc == null )
				throw new NullReferenceException("RepositoryService not available.");

			// Specify the URL to discover.
			string serviceUrl = txtWSUrl.Text;
			string sourceUrl = txtWSUrl.Text;
			if ( !sourceUrl.ToLower().EndsWith("?wsdl") )
				sourceUrl += "?wsdl";

			System.ServiceModel.Description.MetadataExchangeClient mclient;
			System.ServiceModel.Description.MetadataSet mset = null;

			if ( sourceUrl.StartsWith("http") ) {
				//mclient = new System.ServiceModel.Description.MetadataExchangeClient
				//    (new Uri(sourceUrl), System.ServiceModel.Description.MetadataExchangeClientMode.HttpGet);
				mclient = new MetadataExchangeClient("metadataBinding");
				mclient.MaximumResolvedReferences = 100;
				try {
					mset = mclient.GetMetadata(new Uri(sourceUrl), System.ServiceModel.Description.MetadataExchangeClientMode.HttpGet);
				} catch ( Exception ex ) {
					if ( ex.InnerException != null )
						MessageBox.Show(ex.InnerException.Message, "Discover WebService", MessageBoxButtons.OK, MessageBoxIcon.Error);
					else
						MessageBox.Show(ex.Message, "Discover WebService", MessageBoxButtons.OK, MessageBoxIcon.Error);
					return;
				}
			} else {
				MessageBox.Show("Please enter an address for the web service.", "Discover Web Service", MessageBoxButtons.OK, MessageBoxIcon.Information);
				return;
			}
			_wsdl = null;

			#region OLD: use DiscoveryClientProtocol
			//DiscoveryClientProtocol client = new DiscoveryClientProtocol();
			//// Use default credentials to access the URL being discovered.
			//client.Credentials = CredentialCache.DefaultCredentials;


			//try {
			//    DiscoveryDocument doc;

			//    // Discover the URL for any discoverable documents. 
			//    doc = client.DiscoverAny(sourceUrl);

			//    // Resolve all possible references from the supplied URL.
			//    client.ResolveAll();
			//} catch ( Exception e2 ) {
			//    MessageBox.Show(e2.Message); ;
			//}
			//MessageBox.Show(client.Documents.Count.ToString() + " documents discovers.");
			//// get wsdl document
			//foreach ( DictionaryEntry entry in client.Documents ) {
			//    if ( entry.Value is ServiceDescription ) {
			//        _wsdl = (ServiceDescription)entry.Value;
			//        break;
			//    }
			//}
			#endregion

			System.ServiceModel.Description.WsdlImporter importer =
				new System.ServiceModel.Description.WsdlImporter(mset);
			if ( importer.WsdlDocuments.Count > 0 ) {
				_wsdl = importer.WsdlDocuments[0];
			}

			// found wsdl document?
			if ( _wsdl != null ) {
				string nameCallbackInterface = null;
				CodeTypeDeclaration codeTypeClient = null;
				CodeTypeDeclaration codeTypeCallbackInterface = null;
				XmlSchemaSet xsdSet = createXmlSchemaSet();

				//add WSDL Document Namespaces to the Schema Builder
				foreach ( XmlSchema xsd in _wsdl.Types.Schemas ) {
					if ( !xsdSet.Contains(xsd.TargetNamespace) )
						xsdSet.Add(xsd);
				}
				foreach ( XmlSchema xsd in importer.XmlSchemas.Schemas() ) {
					if ( !xsdSet.Contains(xsd.TargetNamespace) )
						xsdSet.Add(xsd);
				}
				xsdSet.Compile();
				//_wsdl.Types.Schemas.Clear();
				foreach ( XmlSchema xsd in xsdSet.Schemas() ) {
					_wsdl.Types.Schemas.Add(xsd);
				}
				_wsdl.Types.Schemas.Compile(null, true);

				// generate contact code
				System.CodeDom.CodeCompileUnit codeContract = new System.CodeDom.CodeCompileUnit();
				System.ServiceModel.Description.ServiceContractGenerator generator =
					new System.ServiceModel.Description.ServiceContractGenerator(codeContract);
				generator.Options = ServiceContractGenerationOptions.AsynchronousMethods | ServiceContractGenerationOptions.ClientClass; //System.ServiceModel.Description.ServiceContractGenerationOptions.None;
				generator.NamespaceMappings.Add(_wsdl.TargetNamespace, _wsdl.Name + "Contract");
				generator.NamespaceMappings.Add("*", _wsdl.Name + "Contract");
				generator.NamespaceMappings.Add("", _wsdl.Name + "Contract");
				System.ServiceModel.Description.ContractDescription cdesc =
					importer.ImportContract(_wsdl.PortTypes[0]);
				System.CodeDom.CodeTypeReference typeRef =
					generator.GenerateServiceContractType(cdesc);

				string codestrContract = "";
				using ( StringWriter sw = new StringWriter() ) {
					Microsoft.CSharp.CSharpCodeProvider csProvider = new Microsoft.CSharp.CSharpCodeProvider();
					System.CodeDom.Compiler.CodeGeneratorOptions options = new System.CodeDom.Compiler.CodeGeneratorOptions();
					options.BlankLinesBetweenMembers = true;
					options.BracingStyle = "C";
					options.ElseOnClosing = true;
					options.IndentString = "\t";
					csProvider.GenerateCodeFromCompileUnit(codeContract, sw, options);
					codestrContract = sw.ToString();
				}

				// save metadata
				string strMetaData = "";
				using ( StringWriter sw = new StringWriter() )
				using ( XmlWriter xw = XmlWriter.Create(sw) ) {
					mset.WriteTo(xw);
					xw.Flush();
					strMetaData = sw.ToString();
				}

				// set webservice values
				ws.Name = string.IsNullOrEmpty(_wsdl.Name) ? _wsdl.Services[0].Name : _wsdl.Name;
				ws.Uri = txtWSUrl.Text;
				ws.Namespace = _wsdl.TargetNamespace;
				ws.Description = string.IsNullOrEmpty(_wsdl.Documentation) ? _wsdl.Services[0].Documentation : _wsdl.Documentation;
				ws.ContractCSharpCode = codestrContract;
				ws.MetaData = strMetaData;
				ws.InterfaceFullName = typeRef.BaseType;
				#region find generated client fullname
				foreach ( CodeNamespace codeNS in codeContract.Namespaces ) {
					foreach ( CodeTypeDeclaration codeType in codeNS.Types ) {
						if ( codeType.IsInterface ) {
							if ( nameCallbackInterface == null ) {
								foreach ( CodeAttributeDeclaration codeattrib in codeType.CustomAttributes ) {
									if ( codeattrib.AttributeType.BaseType.EndsWith(".ServiceContractAttribute") ) {
										foreach ( CodeAttributeArgument attribarg in codeattrib.Arguments ) {
											if ( attribarg.Name == "CallbackContract" ) {
												nameCallbackInterface = ( (CodeTypeOfExpression)attribarg.Value ).Type.BaseType;
												string[] split = nameCallbackInterface.Split('.');
												nameCallbackInterface = split[split.Length - 1];
											}
										}
									}
								}
							} else if ( codeType.Name == nameCallbackInterface ) {
								codeTypeCallbackInterface = codeType;
							}
						}
						foreach ( CodeTypeReference codeTypeRef in codeType.BaseTypes ) {
							if ( codeTypeRef.BaseType.Contains("ClientBase") ) {
								ws.ClientFullName = codeNS.Name + "." + codeType.Name;
								codeTypeClient = codeType;
								//goto EndSearchClient;
							}
						}
					}
				}
				//EndSearchClient:
				#endregion

				using ( StringWriter sw = new StringWriter() ) {
					_wsdl.Write(sw);
					XmlDocument xd = new XmlDocument();
					xd.LoadXml(sw.ToString());
					ws.WSDL = xd;
				}

				// get webmethods (operations)
				dgvWebMethods.DataSource = null;
				_webmethods.Clear();

				foreach ( PortType porttype in _wsdl.PortTypes ) {
					foreach ( Operation op in porttype.Operations ) {
						bool bSC;
						bool bIsCallbackMethod = false;
						Repository.WebMethod meth = repSvc.GetItem(
							OpenComposite.EII.Repository.ItemType.WebMethod, true, _idRepository, false, false, out bSC)
							as Repository.WebMethod;
						meth.Name = op.Name;
						meth.Description = op.Documentation;
						meth.PortType = op.PortType.Name;
						meth.WebServiceID = ws.ID;
						meth.Action = findAction(op);

						System.ServiceModel.Description.OperationDescription wsop = cdesc.Operations.Find(meth.Name);
						System.ServiceModel.Description.MessageDescription mdIn = null, mdOut = null;
						foreach ( System.ServiceModel.Description.MessageDescription md in wsop.Messages ) {
							if ( md.Direction == System.ServiceModel.Description.MessageDirection.Input )
								mdIn = md;
							else if ( md.Direction == System.ServiceModel.Description.MessageDirection.Output )
								mdOut = md;
						}
						CodeMemberMethod methodClient = findMethodInClass(codeTypeClient, meth.Name, meth.Action);
						if ( methodClient == null && codeTypeCallbackInterface != null ) {
							methodClient = findMethodInClass(codeTypeCallbackInterface, meth.Name, meth.Action);
							if ( methodClient != null ) bIsCallbackMethod = true;
						}
						if ( methodClient != null ) {
							if ( mdIn != null && mdIn.Body != null ) {
								// get input types and names
								string typenames = "", varnames = "";
								foreach ( CodeParameterDeclarationExpression paramDecl in methodClient.Parameters ) {
									if ( typenames != "" ) typenames += ";";
									if ( varnames != "" ) varnames += ";";

									typenames += paramDecl.Type.BaseType;
									if ( paramDecl.Type.ArrayRank > 0 ) {
										typenames += "[";
										for ( int i = 0; i < paramDecl.Type.ArrayRank - 1; i++ ) {
											typenames += ",";
										}
										typenames += "]";
									}
									varnames += paramDecl.Name;
								}
								meth.InputWrapperName = string.Format("{0}:{1}", mdIn.Body.WrapperNamespace, mdIn.Body.WrapperName);
								meth.InputTypeName = typenames;
								meth.InputVariableName = varnames;
							}
							if ( mdOut != null && mdOut.Body != null ) {
								// get output types and names
								meth.OutputWrapperName = string.Format("{0}:{1}", mdOut.Body.WrapperNamespace, mdOut.Body.WrapperName);
								if ( bIsCallbackMethod ) {
									string typenames = "", varnames = "";
									foreach ( CodeParameterDeclarationExpression paramDecl in methodClient.Parameters ) {
										if ( typenames != "" ) typenames += ";";
										if ( varnames != "" ) varnames += ";";

										typenames += paramDecl.Type.BaseType;
										if ( paramDecl.Type.ArrayRank > 0 ) {
											typenames += "[";
											for ( int i = 0; i < paramDecl.Type.ArrayRank - 1; i++ ) {
												typenames += ",";
											}
											typenames += "]";
										}
										varnames += paramDecl.Name;
									}
									meth.OutputTypeName = typenames;
									meth.OutputVariableName = varnames;
								} else {
									meth.OutputTypeName = methodClient.ReturnType.BaseType;
								}
								if ( methodClient.ReturnType.ArrayRank > 0 ) {
									meth.OutputTypeName += "[";
									for ( int i = 0; i < methodClient.ReturnType.ArrayRank - 1; i++ ) {
										meth.OutputTypeName += ",";
									}
									meth.OutputTypeName += "]";
								}
								if ( mdOut.Body.ReturnValue != null || mdOut.Body.Parts.Count > 0 ) {
									meth.OutputVariableName = getOutputVarName(getMessageSchema(op.Messages.Output.Message));// mdOut.Body.ReturnValue.Name;
									if ( !bIsCallbackMethod && !meth.OutputVariableName.Contains(mdOut.Body.ReturnValue.Name) ) {
										meth.OutputVariableName += "/" + mdOut.Body.ReturnValue.Name;
									}
								}
							}
						} else {
							#region Get Input / Output Types and Names by Web Method Message
							System.Reflection.FieldInfo baseType = null;
							if ( mdIn != null && mdIn.Body != null && mdIn.Body.Parts.Count > 0 ) {
								string typenames = "", varnames = "";
								foreach ( MessagePartDescription part in mdIn.Body.Parts ) {
									baseType = part.GetType().GetField("baseType", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
									if ( typenames != "" ) typenames += ";";
									if ( varnames != "" ) varnames += ";";
									object typeobj = baseType.GetValue(part);
									string typenm = null;
									if ( typeobj != null ) {
										typenm = typeobj.ToString();
										foreach ( XmlQualifiedName xqn in xsdSet.GlobalTypes.Names ) {
											if ( xqn.Name == typenm ) {
												typenm = xqn.ToString();
												break;
											}
										}
									}
									if ( typenm != null )
										typenames += typenm;
									else
										typenames += part.Name;
									varnames += part.Name;
								}
								meth.InputWrapperName = string.Format("{0}:{1}", mdIn.Body.WrapperNamespace, mdIn.Body.WrapperName);
								meth.InputTypeName = typenames;
								meth.InputVariableName = varnames;
							}
							if ( mdOut != null && mdOut.Body != null ) {
								string typenames = "", varnames = "";
								if ( mdOut.Body.Parts.Count > 0 ) {
									foreach ( MessagePartDescription part in mdOut.Body.Parts ) {
										baseType = part.GetType().GetField("baseType", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
										if ( typenames != "" ) typenames += ";";
										if ( varnames != "" ) varnames += ";";
										object typeobj = baseType.GetValue(part);
										string typenm = null;
										if ( typeobj != null ) {
											typenm = typeobj.ToString();
											foreach ( XmlQualifiedName xqn in xsdSet.GlobalTypes.Names ) {
												if ( xqn.Name == typenm ) {
													typenm = xqn.ToString();
													break;
												}
											}
										}
										if ( typenm != null )
											typenames += typenm;
										else
											typenames += part.Name;
										varnames += part.Name;
									}
								}
								if ( mdOut.Body.ReturnValue != null ) {
									MessagePartDescription part = mdOut.Body.ReturnValue;
									baseType = part.GetType().GetField("baseType", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
									if ( typenames != "" ) typenames += ";";
									if ( varnames != "" ) varnames += ";";
									object typeobj = baseType.GetValue(part);
									string typenm = null;
									if ( typeobj != null ) {
										typenm = typeobj.ToString();
										foreach ( XmlQualifiedName xqn in xsdSet.GlobalTypes.Names ) {
											if ( xqn.Name == typenm ) {
												typenm = xqn.ToString();
												break;
											}
										}
									}
									if ( typenm != null )
										typenames += typenm;
									else
										typenames += part.Name;
									varnames += part.Name;
								}
								meth.OutputWrapperName = string.Format("{0}:{1}", mdOut.Body.WrapperNamespace, mdOut.Body.WrapperName);
								meth.OutputTypeName = typenames;
								meth.OutputVariableName = varnames;
							}
							#endregion
						}
						if ( op.Messages.Input != null ) {
							meth.InputSchema = getMessageSchema(op.Messages.Input.Message); //getSchemaFromMessage(op.Messages.Input.Message);
							meth.InputAction = op.Messages.Input.Message.ToString();
						}
						if ( op.Messages.Output != null ) {
							meth.OutputSchema = getMessageSchema(op.Messages.Output.Message);//getSchemaFromMessage(op.Messages.Output.Message);
							meth.OutputAction = op.Messages.Output.Message.ToString();
						}

						_webmethods.Add(meth);
					}
				}
			}
		}

		private string findAction(System.Web.Services.Description.Operation op)
		{
			string action = "";
			foreach ( System.Web.Services.Description.Binding binding in _wsdl.Bindings ) {
				if ( binding.Type.Name == op.PortType.Name ) {
					foreach ( OperationBinding opBinding in binding.Operations ) {
						if ( opBinding.Name == op.Name ) {
							foreach ( object extObj in opBinding.Extensions ) {
								SoapOperationBinding soapBind = extObj as SoapOperationBinding;
								Soap12OperationBinding soap12Bind = extObj as Soap12OperationBinding;
								if ( soapBind != null ) {
									action = soapBind.SoapAction;
									goto End;
								} else if ( soap12Bind != null ) {
									action = soap12Bind.SoapAction;
									goto End;
								}
							}
						}
					}
				}
			}
End:
			return action;
		}
		private CodeMemberMethod findMethodInClass(CodeTypeDeclaration codeClass, string methodName, string actionName)
		{
			CodeMemberMethod resultMethod = null;
			foreach ( CodeTypeMember codeMember in codeClass.Members ) {
				CodeMemberMethod method = codeMember as CodeMemberMethod;
				if ( method == null ) continue;

				string action = "";
				foreach ( CodeAttributeDeclaration attrib in method.CustomAttributes ) {
					if ( attrib.AttributeType.BaseType == typeof(OperationContractAttribute).FullName ) {
						foreach ( CodeAttributeArgument arg in attrib.Arguments ) {
							CodePrimitiveExpression primExpr = arg.Value as CodePrimitiveExpression;
							if ( arg.Name == "Action" && primExpr != null && primExpr.Value != null ) {
								action = primExpr.Value.ToString();
								break;
							}
						}
						if ( action != "" ) break;
					} else if ( attrib.AttributeType.BaseType == typeof(SoapDocumentMethodAttribute).FullName ) {
						foreach ( CodeAttributeArgument arg in attrib.Arguments ) {
							CodePrimitiveExpression primExpr = arg.Value as CodePrimitiveExpression;
							if ( arg.Name == "" && primExpr != null && primExpr.Value != null ) {
								action = primExpr.Value.ToString();
								break;
							}
						}
						if ( action != "" ) break;
					}
				}
				if ( !actionName.Contains("/") ) {
					actionName = "/" + actionName;
				}
				if ( ( string.IsNullOrEmpty(action) && method.Name == methodName ) ||
					 ( action.EndsWith(actionName) && method.Name == methodName ) ) {
					resultMethod = method;
				}
			}
			return resultMethod;
		}
		//private CodeMemberMethod findMethodInClass(CodeTypeDeclaration codeClass, string methodName, string returnTypeName)
		//{
		//    CodeMemberMethod resultMethod = null;
		//    foreach ( CodeTypeMember codeMember in codeClass.Members ) {
		//        CodeMemberMethod method = codeMember as CodeMemberMethod;
		//        if ( method == null ) continue;

		//        if ( method.Name == methodName &&
		//             ( ( string.IsNullOrEmpty(returnTypeName) && method.PrivateImplementationType == null ) ||
		//               ( !string.IsNullOrEmpty(returnTypeName) && method.ReturnType.BaseType.EndsWith("." + returnTypeName) ) ) ) {
		//            resultMethod = method;
		//            break;
		//        } else {
		//            string action = "";
		//            foreach ( CodeAttributeDeclaration attrib in method.CustomAttributes ) {
		//                if ( attrib.AttributeType.BaseType == typeof(OperationContractAttribute).FullName ) {
		//                    foreach ( CodeAttributeArgument arg in attrib.Arguments ) {
		//                        CodePrimitiveExpression primExpr = arg.Value as CodePrimitiveExpression;
		//                        if ( arg.Name == "Action" && primExpr != null && primExpr.Value != null ) {
		//                            action = primExpr.Value.ToString();
		//                            break;
		//                        }
		//                    }
		//                    if ( action != "" ) break;
		//                } else if ( attrib.AttributeType.BaseType == typeof(SoapDocumentMethodAttribute).FullName ) {
		//                    foreach ( CodeAttributeArgument arg in attrib.Arguments ) {
		//                        CodePrimitiveExpression primExpr = arg.Value as CodePrimitiveExpression;
		//                        if ( arg.Name == "" && primExpr != null && primExpr.Value != null ) {
		//                            action = primExpr.Value.ToString();
		//                            break;
		//                        }
		//                    }
		//                    if ( action != "" ) break;
		//                }
		//            }
		//            if ( action.EndsWith("/" + methodName) &&
		//                 ( ( string.IsNullOrEmpty(returnTypeName) && method.PrivateImplementationType == null ) ||
		//                   ( !string.IsNullOrEmpty(returnTypeName) && method.ReturnType.BaseType.EndsWith("." + returnTypeName) ) ) ) {
		//                resultMethod = method;
		//            }
		//        }
		//    }
		//    return resultMethod;
		//}
		private string getOutputVarName(XmlSchema xmlSchema)
		{
			string outputVarName = "";
			bool finished = false;
			XmlSchemaElement xse = null;

			do {
				if ( xse == null ) {
					foreach ( XmlSchemaObject xso in xmlSchema.Items ) {
						xse = xso as XmlSchemaElement;
						if ( xse != null ) break;
					}
					if ( xse == null ) break;
				} else {
					if ( outputVarName != "" ) outputVarName += "/";
					outputVarName += xse.Name;
					if ( xse.SchemaType != null ) {
						XmlSchemaComplexType xsct = xse.SchemaType as XmlSchemaComplexType;
						if ( xsct != null ) {
							XmlSchemaGroupBase xsgb = xsct.Particle as XmlSchemaGroupBase;
							if ( xsgb != null && xsgb.Items.Count == 1 && xsgb.Items[0] is XmlSchemaElement ) {
								xse = (XmlSchemaElement)xsgb.Items[0];
							} else {
								finished = true;
							}
						} else {
							finished = true;
						}
					} else {
						finished = true;
					}
				}
			} while ( !finished );

			return outputVarName;
		}

		private XmlSchema getMessageSchema(XmlQualifiedName msgname)
		{
			//get Message from WSDL Document
			System.Web.Services.Description.Message msg = _wsdl.Messages[msgname.Name];

			//create new Schema Builder for assembling the Message Schema
			XmlSchema xsdResult = new XmlSchema();
			xsdResult.ElementFormDefault = XmlSchemaForm.Qualified;

			List<string> lstAddedNS = new List<string>();

			//add WSDL Document Namespaces to the Schema Builder
			foreach ( XmlSchema xsd in _wsdl.Types.Schemas ) {
				if ( !string.IsNullOrEmpty(xsd.TargetNamespace) && !lstAddedNS.Contains(xsd.TargetNamespace) ) {
					xsdResult.Namespaces.Add(string.Format("q{0}", _i), xsd.TargetNamespace);
					lstAddedNS.Add(xsd.TargetNamespace);
					_i++;
				}
			}

			foreach ( MessagePart messagePart in msg.Parts ) {
				XmlSchemaElement xse =
					_wsdl.Types.Schemas.Find(messagePart.Element, typeof(System.Xml.Schema.XmlSchemaElement))
						as XmlSchemaElement;
				if ( xse != null ) {
					xsdResult.TargetNamespace = xse.QualifiedName.Namespace;
					xsdResult.Items.Add(xse);
				}
			}
			return xsdResult;
		}
		private void showInformations()
		{
			Repository.WebService ws = this.RepositoryItem as Repository.WebService;
			if ( ws == null )
				throw new Exception("Repository Item is not a webservice.");
			if ( string.IsNullOrEmpty(ws.Uri) || ws.WSDL == null ) return;

			this.SuspendLayout();
			try {
				if ( ws != null ) {
					txtName.Text = ws.Name;
					txtDesc.Text = ws.Description;
					txtXmlns.Text = ws.Namespace;
				} else {
					txtName.Text = "- Not Available -";
					txtDesc.Text = "";
					txtXmlns.Text = "";
				}
				dgvWebMethods.DataSource = null;
				dgvWebMethods.DataSource = _webmethods;
			} finally {
				this.ResumeLayout(true);
			}

		}

		private XmlSchema getSchema(XmlQualifiedName message,
									DiscoveryClientProtocol client,
									System.Web.Services.Description.ServiceDescription wsdl)
		{
			XmlSchemaSet schemaset = new XmlSchemaSet();
			XmlSchema xsd = null;
			XmlSchemaObject xsdObj = null;
			System.Web.Services.Description.Message msg = wsdl.Messages[message.Name];
			MessagePart part = msg.Parts[0];
			// search in wsdl types
			//wsdl.Types.Schemas.Compile(null, true);
			XmlSchemaElement xsdElement = (XmlSchemaElement)wsdl.Types.Schemas.Find(
				part.Element, typeof(XmlSchemaElement));

			if ( xsdElement != null ) {
				xsdObj = xsdElement;
			} else {
				// search imported documents
				foreach ( XmlSchema schema in wsdl.Types.Schemas ) {
					schemaset.Add(schema);
				}
				schemaset.Compile();

				xsdObj = schemaset.GlobalElements[part.Element];
			}
			if ( xsdObj != null ) {
				xsd = new XmlSchema();
				xsd.Items.Add(xsdObj);
				schemaset.Add(xsd);
				schemaset.Compile();
			}

			start(xsd);

			XmlWriterSettings settings = new XmlWriterSettings();
			settings.Indent = false;
			settings.OmitXmlDeclaration = true;
			settings.ConformanceLevel = ConformanceLevel.Auto;
			using ( StringWriter sw = new StringWriter() )
			using ( XmlWriter xw = XmlWriter.Create(sw, settings) ) {
				xsd.Write(xw, new XmlNamespaceManager(schemaset.NameTable));
				xw.Flush();
				string sXSD = sw.ToString();
			}
			return xsd;
		}
		private void start(XmlSchema schema)
		{
			foreach ( XmlSchemaType type in schema.SchemaTypes.Values ) {
				if ( type is XmlSchemaComplexType ) {
					XmlSchemaComplexType ct = type as XmlSchemaComplexType;
					walkTheParticle(ct.ContentTypeParticle);
				}
			}
			foreach ( XmlSchemaElement el in schema.Elements.Values ) {
				walkTheParticle(el);
			}
			foreach ( XmlSchemaAnnotated xsa in schema.Items ) {
				if ( xsa is XmlSchemaGroup ) {
					XmlSchemaGroup xsg = xsa as XmlSchemaGroup;
					walkTheParticle(xsg.Particle);
				}
			}
		}

		private XmlSchema getSchemaFromMessage(XmlQualifiedName msgname)
		{
			//get Message from WSDL Document
			System.Web.Services.Description.Message msg = _wsdl.Messages[msgname.Name];

			//create new Schema Builder for assembling the Message Schema
			XmlSchema xsdResult = new XmlSchema();
			xsdResult.ElementFormDefault = XmlSchemaForm.Qualified;

			List<string> lstAddedNS = new List<string>();
			XmlSchemaSet xsdSet = new XmlSchemaSet();

			//add WSDL Document Namespaces to the Schema Builder
			foreach ( XmlSchema xsd in _wsdl.Types.Schemas ) {
				//if ( !xsdSet.Contains(xsd.TargetNamespace) ) {
				//    xsdSet.Add(xsd);
				//    xsdSet.Compile();
				//}
				if ( !lstAddedNS.Contains(xsd.TargetNamespace) ) {
					xsdResult.Namespaces.Add(string.Format("q{0}", _i), xsd.TargetNamespace);
					lstAddedNS.Add(xsd.TargetNamespace);
				}
				_i++;
			}

			xsdSet.Compile();
			foreach ( XmlSchema xsd in xsdSet.Schemas() ) {
				//if ( !_wsdl.Types.Schemas.Contains(xsd.TargetNamespace) ) {
				//    _wsdl.Types.Schemas.Add(xsd);
				//}
				if ( !lstAddedNS.Contains(xsd.TargetNamespace) ) {
					xsdResult.Namespaces.Add(string.Format("q{0}", _i), xsd.TargetNamespace);
					lstAddedNS.Add(xsd.TargetNamespace);
				}
				_i++;
			}
			_wsdl.Types.Schemas.Compile(null, true);

			#region process Messages Parts
			foreach ( MessagePart messagePart in msg.Parts ) {
				XmlSchemaElement xse =
					_wsdl.Types.Schemas.Find(messagePart.Element, typeof(System.Xml.Schema.XmlSchemaElement))
						as XmlSchemaElement;
				if ( xse != null ) {
					xsdResult.Items.Add(xse);
					continue;
				}
				if ( messagePart.Type.IsEmpty == false ) {
					//add Type Definition of the Message Part to the Schema Builder
					this.addSchemaTypeToSchema(messagePart.Type, xsdResult);

					xsdResult.TargetNamespace = messagePart.Type.Namespace;
				}

				if ( messagePart.Element.IsEmpty == false ) {
					//get Element from WSDL
					XmlSchemaObject msgPartObject =
						this.getSchemaObjectFromQName(messagePart.Element, true);

					xsdResult.TargetNamespace = messagePart.Element.Namespace;

					if ( msgPartObject is XmlSchemaElement ) {
						//add Element to the Schema Builder
						this.addSchemaElementToSchema((XmlSchemaElement)msgPartObject, xsdResult, false);
					}

				}

				if ( messagePart.Type.IsEmpty == false ) {
					//create new Element representing the MessagePart Name
					XmlSchemaElement schemaElement = new XmlSchemaElement();
					schemaElement.Name = messagePart.Name;
					schemaElement.SchemaTypeName = messagePart.Type;
					xsdResult.Items.Add(schemaElement);
				}
			}
			#endregion

			//compile Message Schema
			//this.checkXmlSchema(xsdResult);

			//return Content of the built Message Schema
			return xsdResult;
		}
		private void processXmlSchemaParticle(XmlSchema xsdResult, XmlSchemaParticle part)
		{
			//<xs: element ... />
			if ( part is XmlSchemaElement ) {
				if ( ( (XmlSchemaElement)part ).SchemaTypeName.IsEmpty == false ) {
					this.addSchemaTypeToSchema(( (XmlSchemaElement)part ).SchemaTypeName, xsdResult);
				}
				if ( ( (XmlSchemaElement)part ).SchemaType is XmlSchemaComplexType ) {
					XmlSchemaComplexType ct = ( (XmlSchemaElement)part ).SchemaType as XmlSchemaComplexType;
					if ( ct.ContentTypeParticle is XmlSchemaSequence ) {
						//get Child Sequence from Complex Type
						XmlSchemaSequence seq = (XmlSchemaSequence)ct.ContentTypeParticle;

						#region process Elements of the Sequence
						foreach ( XmlSchemaParticle partCT in seq.Items ) {
							processXmlSchemaParticle(xsdResult, partCT);
						}
						#endregion
					} else if ( ct.ContentTypeParticle is XmlSchemaChoice ) {
						//get Child Choice from Complex Type
						XmlSchemaChoice choice = (XmlSchemaChoice)ct.ContentTypeParticle;
						foreach ( XmlSchemaParticle partCT in choice.Items ) {
							processXmlSchemaParticle(xsdResult, partCT);
						}
					}
				}

				if ( ( (XmlSchemaElement)part ).RefName.IsEmpty == false ) {
					XmlSchemaElement refElement = (XmlSchemaElement)
						this.getSchemaObjectFromQName(( (XmlSchemaElement)part ).RefName,
						true);
					refElement.Namespaces.Add("", refElement.QualifiedName.Namespace);
					this.addSchemaElementToSchema(refElement, xsdResult, false);
				}
			}

			//<xs:any namespace='a_namespace' />
			if ( part is XmlSchemaAny ) {
				if ( _wsdl.Types.Schemas[( (XmlSchemaAny)part ).Namespace] != null ) {
					XmlSchema anyRefSchema = _wsdl.Types.Schemas[( (XmlSchemaAny)part ).Namespace];

					foreach ( XmlSchemaObject anyObj in anyRefSchema.Items ) {
						xsdResult.Items.Add(anyObj);
					}
					if ( xsdResult.TargetNamespace == null || xsdResult.TargetNamespace == string.Empty ) {
						xsdResult.TargetNamespace = anyRefSchema.TargetNamespace;
					}
				}
			}
		}
		private bool addSchemaTypeToSchema
			(XmlQualifiedName typename, XmlSchema xsdResult)
		{
			XmlSchemaType schemaType = this.getSchemaTypeFromType(typename);
			if ( schemaType == null )
				return false;

			if ( schemaType is XmlSchemaComplexType ) {
				if ( ( (XmlSchemaComplexType)schemaType ).ContentTypeParticle is XmlSchemaSequence ) {
					XmlSchemaSequence seq = (XmlSchemaSequence)
						( (XmlSchemaComplexType)schemaType ).ContentTypeParticle;
					foreach ( XmlSchemaObject item in seq.Items ) {
						if ( item is XmlSchemaElement ) {
							if ( ( (XmlSchemaElement)item ).QualifiedName != typename ) {
								//check if Element already exists in Schema
								bool elementAlreadyAdded = this.checkSchemaObjectExists(
									( (XmlSchemaElement)item ).QualifiedName, xsdResult);
								//process Element
								this.addSchemaElementToSchema((XmlSchemaElement)item,
									xsdResult, true);
							}
						}
						if ( item is XmlSchemaType ) {
							this.addSchemaTypeToSchema(
							  ( (XmlSchemaType)item ).QualifiedName, xsdResult);
						}
					}
				}
			}
			if ( xsdResult.TargetNamespace == null
				| xsdResult.TargetNamespace == string.Empty ) {
				if ( schemaType is XmlSchemaType ) {
					xsdResult.TargetNamespace =
						( (XmlSchemaType)schemaType ).QualifiedName.Namespace;
				}
			}
			if ( xsdResult.Items.Contains(schemaType) == false ) {
				xsdResult.Items.Add(schemaType);
			}

			return true;
		}
		/// <summary>
		/// Adds Element that is specified by ElementName to the SchemaBuilder
		/// </summary>
		/// <param name="Element">Xml Element that is to add</param>
		/// <param name="SchemaBuilder"></param>
		/// <param name="ReadOnly">Flag that determines, whether the collected Elements 
		/// Information have to be written into the SchemaBuilder or not. Important for processing
		/// nested Elements</param>
		private void addSchemaElementToSchema
			(XmlSchemaElement element, XmlSchema xsdResult, bool readOnly)
		{

			//process Element's Type
			if ( element.SchemaTypeName.IsEmpty == false ) {
				this.addSchemaTypeToSchema(element.SchemaTypeName, xsdResult);
			}
			//process Element's Reference
			if ( element.RefName.IsEmpty == false ) {
				XmlSchemaElement refElement = (XmlSchemaElement)
					this.getSchemaObjectFromQName(element.RefName, true);
			}


			#region get nested Element Content

			if ( !( element.ElementSchemaType is XmlSchemaComplexType ) ) {
				//process Simple Type
				if ( element.ElementSchemaType is XmlSchemaSimpleType ) {
					if ( !this.addSchemaTypeToSchema(element.SchemaTypeName, xsdResult) &&
						 element.Parent is XmlSchema )
						xsdResult.Items.Add(element);
				}
				return;
			}

			//process Complex Type
			XmlSchemaComplexType complType = (XmlSchemaComplexType)element.ElementSchemaType;

			//assign Complex Type to Element of Interest
			//			schemaElement.SchemaType = complType;

			//if Child is Sequence
			if ( complType.ContentTypeParticle is XmlSchemaSequence ) {
				//get Child Sequence from Complex Type
				XmlSchemaSequence seq = (XmlSchemaSequence)complType.ContentTypeParticle;

				#region process Elements of the Sequence
				foreach ( XmlSchemaParticle part in seq.Items ) {
					processXmlSchemaParticle(xsdResult, part);
				}
				#endregion
			} else if ( complType.ContentTypeParticle is XmlSchemaChoice ) {
				//get Child Choice from Complex Type
				XmlSchemaChoice choice = (XmlSchemaChoice)complType.ContentTypeParticle;
				foreach ( XmlSchemaParticle part in choice.Items ) {
					processXmlSchemaParticle(xsdResult, part);
				}
			}
			#endregion


			if ( readOnly == false ) {
				//add Element to Schema Builder
				if ( xsdResult.Items.Contains(element) == false ) {
					element.Namespaces.Add("tns", element.QualifiedName.Namespace);
					xsdResult.Items.Add(element);
				}
			}
		}
		private XmlSchemaObject getSchemaObjectFromQName
			(XmlQualifiedName QName, bool ObjectIsElement)
		{
			XmlSchema schema = _wsdl.Types.Schemas[QName.Namespace];
			//schema can be null for simple Type Namespaces
			if ( schema == null ) {
				return null;
			}

			foreach ( XmlSchemaObject sObj in schema.Items ) {
				if ( sObj.GetType().GetProperty("QualifiedName") == null ) {
					continue;
				}
				if ( (XmlQualifiedName)( sObj.GetType().GetProperty("QualifiedName")
					.GetValue(sObj, null) ) == QName
					&&
					( ObjectIsElement == true ? ( sObj is XmlSchemaElement ) : !( sObj is XmlSchemaElement ) ) ) {
					return sObj;
				}
			}

			return null;
		}
		private XmlSchemaType getSchemaTypeFromType(XmlQualifiedName typeName)
		{
			return (XmlSchemaType)this.getSchemaObjectFromQName(typeName, false);
		}
		private bool checkSchemaObjectExists(XmlQualifiedName QName, XmlSchema schema)
		{
			foreach ( XmlSchemaObject sObj in schema.Items ) {
				if ( sObj.GetType().GetProperty("QualifiedName") != null ) {
					if ( (XmlQualifiedName)sObj.GetType().GetProperty("QualifiedName")
							.GetValue(sObj, null) == QName ) {
						return true;
					}
				}
			}
			return false;
		}
		private void checkXmlSchema(XmlSchema schema)
		{
			//20050509
			//string schemaContentString = PEPExplorer.GetXmlSchemaContent(XmlSchema);
			//System.IO.MemoryStream memStream = new System.IO.MemoryStream();
			//byte[] schemaContentData =
			//    System.Text.Encoding.ASCII.GetBytes(schemaContentString);
			//memStream.Write(schemaContentData, 0, schemaContentData.Length);
			//memStream.Position = 0;
			//XmlSchema dummySchema = XmlSchema.Read(memStream,
			//    new ValidationEventHandler(XmlValEventHandler));

			XmlSchemaSet xsdset = new XmlSchemaSet();
			xsdset.XmlResolver = null;
			xsdset.Add(schema);
			xsdset.Compile();

			return;
		}

		private void walkTheParticle(XmlSchemaParticle particle)
		{
			if ( particle is XmlSchemaElement ) {
				XmlSchemaElement elem = particle as XmlSchemaElement;

				// todo: insert your processing code here

				if ( elem.RefName.IsEmpty ) {
					XmlSchemaType type = (XmlSchemaType)elem.ElementSchemaType;
					if ( type is XmlSchemaComplexType ) {
						XmlSchemaComplexType ct = type as XmlSchemaComplexType;
						if ( ct.QualifiedName.IsEmpty ) {
							walkTheParticle(ct.ContentTypeParticle);
						} else {
							elem.SchemaType = ct;
							elem.SchemaTypeName = XmlQualifiedName.Empty;
							walkTheParticle(ct.ContentTypeParticle);
						}
					}
				}
			} else if ( particle is XmlSchemaGroupBase ) {
				//xs:all, xs:choice, xs:sequence
				XmlSchemaGroupBase baseParticle = particle as XmlSchemaGroupBase;
				foreach ( XmlSchemaParticle subParticle in baseParticle.Items ) {
					walkTheParticle(subParticle);
				}
			}
		}

		private void showXmlString(string xml)
		{
			XmlDocument xd = new XmlDocument();
			formXmlViewer frm = new formXmlViewer();
			xd.LoadXml(xml);
			frm.XmlDocument = xd;
			frm.ShowDialog();
		}

		//private System.Web.Services.Description.ServiceDescription requestWSDLFromSoapService(Uri uri)
		//{
		//    System.Web.Services.Description.ServiceDescription sdesc = null;

		//    try {
		//        SoapWsdlProxy wp = new SoapWsdlProxy(uri);
		//        WSE2.SoapEnvelope se = wp.RequestDescription();

		//        if ( se != null && se.Body != null && se.Body.FirstChild != null ) {
		//            using( MemoryStream ms = new MemoryStream() )
		//            using ( XmlWriter xw = XmlWriter.Create(ms) ) {
		//                se.Body.FirstChild.WriteTo(xw);
		//                xw.Flush();
		//                ms.Position = 0;
		//                sdesc = System.Web.Services.Description.ServiceDescription.Read(ms);
		//            }
		//        }
		//    } catch {
		//        sdesc = null;
		//    }
		//    return sdesc;
		//}
		private XmlSchemaSet createXmlSchemaSet()
		{
			XsdDataContractExporter ex = new XsdDataContractExporter();
			ex.Export(typeof(OpenComposite.EII.Designer.Workflow.Help));
			XmlSchemaSet xsdset = ex.Schemas;
			XmlSchema xsdRemove = null;
			foreach ( XmlSchema xsd in xsdset.Schemas() ) {
				if ( xsd.Elements.Contains(new XmlQualifiedName("Help", xsd.TargetNamespace)) ) {
					xsdRemove = xsd;
				}
			}
			xsdset.Remove(xsdRemove);
			return xsdset;
		}

		#endregion

		#region Event Handlers
		//private void btnOK_Click(object sender, EventArgs e)
		//{
		//    saveClose();
		//}
		private void btnDiscover_Click(object sender, EventArgs e)
		{
			this.Cursor = Cursors.WaitCursor;
			try {
				this.Refresh();
				discoverWS();
				showInformations();
				this.Cursor = Cursors.Default;
			} catch ( Exception ex ) {
				this.Cursor = Cursors.Default;
				MessageBox.Show(ex.Message, ex.Source, MessageBoxButtons.OK, MessageBoxIcon.Error);
			} finally {
				this.Refresh();
			}
		}
		private void btnShowWSDL_Click(object sender, EventArgs e)
		{
			Repository.WebService ws = this.RepositoryItem as Repository.WebService;
			if ( ws == null )
				throw new Exception("Repository Item is not a webservice.");

			if ( ws != null ) {
				formXmlViewer frm = new formXmlViewer();
				frm.XmlDocument = ws.WSDL;
				frm.ShowDialog();
			}
		}

		private void dgvWebMethods_MouseDown(object sender, MouseEventArgs e)
		{
			System.Windows.Forms.DataGridView.HitTestInfo hti = dgvWebMethods.HitTest(e.X, e.Y);
			if ( hti.RowIndex >= 0 && hti.RowIndex < dgvWebMethods.RowCount ) {
				Repository.WebMethod meth = dgvWebMethods.Rows[hti.RowIndex].DataBoundItem as Repository.WebMethod;
				if ( meth != null ) {
					if ( hti.ColumnIndex == colInputSchema.Index ) {
						showXmlString(meth.InputSchemaString);
					} else if ( hti.ColumnIndex == colOutputSchema.Index ) {
						showXmlString(meth.OutputSchemaString);
					}
				}
			}
		}

		#endregion

	}

}
